/**
 * @author Xiao Xin
 * @version 1.0.0
 * @date 20210310
 * @copyright MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
 */
var SelfEncodingBase = require('../encoding/SelfEncodingBase').SelfEncodingBase
var Encoder = require('../encoding/Encoder').Encoder
var Block = require('../encoding/Block').Block
var TLV = require('../encoding/TLV')
var {InitialAble,TlvComponentBase} = require('./TlvComponentBase')
var aggregation = require('../common/aggregation')//实现了多继承

/**
 * @description 表示网络包负载
 * 1.格式如下：
 * Payload = PAYLOAD-TYPE TLV-LENGTH *OCTET
 * 2.详情参见：http://gitea.qjm253.cn/PKUSZ-future-network-lab/minlib/src/branch/master/docs/PacketFormat.md#4-signature
 *@ todo 还继承了一个类 TLvComponentBase、InitialAble
 */
class Payload extends aggregation(TlvComponentBase,InitialAble,SelfEncodingBase){
  constructor(){
    super()
    this.value = new ArrayBuffer(0)
  }

  /**
   * @description 根据 TLV Block 初始化一个 Payload
   * @param {Block} block
   */
  buildPayloadByBlock(block){
    try {
      this.wireDecode(block)
    } catch (error) {
      throw error
    }
  }

  /**
   * @description 得到Payload TLV中实际包含的数据
   * @return {buffer}
   */
  getValue(){
    return this.value
  }

  /**
   * @description 设置 Payload TLV 中的Value
   * @param value
   */
  setValue(value){
    if(value instanceof Uint8Array){
      value = value.buffer
    }
    this.value = value
    // 此处的value是ArrayBuffer类型的,但Uint8Array也可以毫无阻碍的赋值，可能产生问题，是否添加一个类型判断？？
      // 臣附议
    this.doInitial()
  }

  /**
   * @description 将Payload线速编码为一个 TLV
   * @param {Encoder} encoder
   * @return {number}
   */
  wireEncode(encoder){
    let totalLength = 0
		try {
			//编码 TLV-VALUE
			let tmpLen = encoder.prependByteArray(this.value, BigInt(this.value.byteLength))
			totalLength += tmpLen

			//编码 TLV-LENGTH
			tmpLen = encoder.prependVarNumber(BigInt(totalLength))
			totalLength += tmpLen

			//编码 TLV-TYPE
			tmpLen = encoder.prependVarNumber(TLV.ComponentType.TlvPayload)
			totalLength += tmpLen

			return totalLength
		} catch (error) {
			throw error
		}
  }

  /**
	 * @description 从 TLV Block 中解码出一个 Payload
	 * @param {Block} block
	 */
	wireDecode(block){
		try {
			//检查Type是否正确
			TLV.expectType(block.getType(),TLV.ComponentType.TlvPayload)
			this.value = block.getValue()
		} catch (error) {
			throw error
		}
	}
}

/**
 * @description 根据一个TLV Block 创建一个 Payload
 * @param {Block} block 
 * @return {Payload}
 */
function createPayloadByBlock(block){
  var payload = new Payload()
  try {
    payload.buildPayloadByBlock(block)
    return payload
  } catch (error) {
    throw error
  }
}

module.exports = {
  Payload: Payload,
  createPayloadByBlock: createPayloadByBlock
}

